class ListInstance:
    """
    Примесный класс, реализующий получение форматированной строки при вызове
    функций print() и str() с экземпляром в виде аргумента, через наследование
    метода __str__, реализованного здесь; отображает только атрибуты
    экземпляра; self – экземпляр самого нижнего класса в дереве наследования;
    во избежание конфликтов с именами атрибутов клиентских классов использует
    имена вида __X
    """

    def __attrnames(self):
        result = ''
        for attr in sorted(self.__dict__):
            result += '\t Attribute name: {0}, value: {1}\n'.format(attr, self.__dict__[attr])
        return result

    def __str__(self):
        return '<Instance of {0}, address {1}:> \n{2}'.format(self.__class__.__name__, id(self), self.__attrnames())


class ListInherited:
    """
    Использует функцию dir() для получения списка атрибутов самого экземпляра
    и атрибутов, унаследованных экземпляром от его классов; в Python 3.0
    выводится больше имен атрибутов, чем в 2.6, потому что классы нового стиля
    в конечном итоге наследуют суперкласс object; метод getattr() позволяет
    получить значения унаследованных атрибутов, отсутствующих в self.__dict__;
    реализует метод __str__, а не __repr__, потому что в противном случае
    данная реализация может попасть в бесконечный цикл при выводе связанных
    методов!
    """

    def __attrnames(self):
        """
        Получает атрибуты класса
        :return: строка, содержащая пару атрибут=значение
        :rtype: строка
        """
        result = ''
        for attr in dir(self):
            if attr[:2] == '__' and attr[-2:] == '__':
                result += '\tname: {0}=<>\n'.format(attr)
            else:
                result += '\tname: {0}={1}\n'.format(attr, getattr(self, attr))
        return result

    def __str__(self):
        return '<Instance of {0}, address {1}:> \n{2}'.format(self.__class__.__name__, id(self), self.__attrnames())


class ListTree:
    """
    Примесный класс, в котором метод __str__ просматривает все дерево классов
    и составляет список атрибутов всех объектов, находящихся в дереве выше
    self; вызывается функциями print(), str() и возвращает сконструированную
    строку со списком; во избежание конфликтов с именами атрибутов клиентских
    классов использует имена вида __X; для рекурсивного обхода суперклассов
    использует выражение-генератор; чтобы сделать подстановку значений более
    очевидной, использует метод str.format()
    """

    def __str__(self):
        self.__visited = {}
        return '<instance of {0}, address {1}:\n{2}{3}>'.format(
            self.__class__.__name__,
            id(self),
            self.__attrnames(self, 0),
            self.__listclass(self.__class__, 4))

    def __listclass(self, aClass, indent):
        dots = '.' * indent
        if aClass in self.__visited:
            return '\n{0} Class {1}: adress {2}: (see above)>\n'.format(
                dots,
                aClass.__name__,
                id(aClass)
            )
        else:
            self.__visited[aClass] = True
            genabove = (self.__listclass(c, indent + 4)
                        for c in aClass.__bases__)
            return '\n{0} Class {1}, address {2}: \n {3}\n {4}\n {5}\n>'.format(
                dots,
                aClass.__name__,
                id(aClass),
                self.__attrnames(aClass, indent),
                ''.join(genabove),
                dots
            )

    @staticmethod
    def __attrnames(obj, indent):
        spaces = ' ' * (indent + 4)
        result = ''
        for attr in sorted(obj.__dict__):
            if attr.startswith('__') and attr.endswith('__'):
                result += spaces + '{0} = <>\n'.format(attr)
            else:
                result += spaces + '\n{0} = {1}\n'.format(attr, getattr(obj, attr))
        return result
